//
// Created by wt on 2020/8/28.
//

#ifndef IIMTDriverCPP_IIMTDriver_H
#define IIMTDriverCPP_IIMTDriver_H

#include <iostream>
#include <memory>
#include <QtWidgets>
#include <QTcpSocket>
#include <functional>
#include <driver/IIMTScript.h>
#include <QDebug>
#include <driver/data.h>
#include <memory.h>
#include <driver/utils.h>
#include <queue>
#include <unistd.h>
#include <QJsonParseError>
#include <QVariantMap>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonValue>
#include <QJsonParseError>
#include <QMap>
#include <QString>
#include <QCoreApplication>
#include <QDataStream>
#include <QTimer>
/**
 * sukai
 * QTcpSocket 机器臂驱动
 */
using namespace std;
class IIMTDriver :  public QWidget {
 //  Q_OBJECT
private:
    //私有三个构造函数
    IIMTDriver(QWidget *parent = 0);
    IIMTDriver(const  IIMTDriver&);
    IIMTDriver operator=(const  IIMTDriver&);
    //定义静态变量
  //  static shared_ptr<IIMTDriver> instance;
    // 定义静态变量
      static IIMTDriver * instance;
       static mutex *m ;
    //QTcpSocket
    QTcpSocket socket;
    //创建脚本对象
    IIMTScript script;
    QTimer timer ;

    //连接回调函数
    function<void()> connectCallBack;
    //断开连接回调
    function<void()> disConnectCallBack;

    //指令队列
    queue<QString> instructionMessageQueue;
    //-----------------传到函数传到ui去------------------------
    //sukai 获取地图名称 传到函数传到ui去
    function<void(QList<QMap<QString,std::vector<std::string>>> mapNames_list)> mapNames_list_CallBack=nullptr;
    //sukai 到达点位后返回的数据 传到函数传到ui去
    function<void(ArriveRobot arriveRobot)> arriveRobot_CallBack=nullptr;
    //sukai 机器人的一些基本信息 传到函数传到ui去
    function<void(Robot_info robot_info)> robot_info_CallBack=nullptr;
    //sukai 小车的运行状态 传到函数传到ui去
    function<void(QString robot_status)> robot_status_CallBack=nullptr;
    //sukai 保存地图后反馈传到ui去
    function<void(SaveGmappingMap saveGmappingMap)> robot_saveGmappingMap_CallBack=nullptr;
    //sukai 路点数据 传到函数传到ui去
    function<void(QList<TestInfo> testInfos)> maptestInfos_list_CallBack=nullptr;
    //sukai 字典数据 传到函数传到ui去
    function<void(QList<Dictionaries> dictionaries_s)> mapdictionarie_list_CallBack=nullptr;
    //sukai 执行路点任务 传到函数传到ui去
    function<void(QList<TaskPOSE> taskPOSEs)> maptaskPOSEMaps_list_CallBack=nullptr;
    //sukai 定时任务 传到函数传到ui去
    function<void(QList<Table_Task> Time_Tasks)> mapTable_time_task_list_CallBack=nullptr;
    //------------------传到编辑类------------------------
    //sukai 路点数据 传到编辑类 KSDemoDlg 中
    function<void(QList<QMap<QString, QString> >maptestInfos_list)> kSDemoDlg_testInfos_list_CallBack=nullptr;
    //sukai 字典数据 传到编辑类 KSDemoDlgtaskparamer 中
    function<void(QList<QMap<QString, QString> > mapdictionarie_list)> kSDemoDlg_dictionarie_list_CallBack=nullptr;
    //sukai 执行路点任务 传到编辑类 KSDemoDlgtask 中
    function<void(QList<QMap<QString, QString> > maptaskPOSEMaps_list)> kSDemoDlg_task_pose_list_CallBack=nullptr;
    //sukai 定时任务 传到编辑类 KSDemoDlgtaskTime 中
    function<void(QList<QMap<QString, QString> > mapTable_TaskMaps_list)> kSDemoDlg_task_time_list_CallBack=nullptr;
    //sukai 虚拟墙 传到编辑类 KSDemoDlgtaskTime 中
    function<void(QList<QMap<QString, QString> > kSDemoDlg_task_costmapLayer_list_CallBack)> kSDemoDlg_task_costmapLayer_list_CallBack=nullptr;


    //sukai 获取所有运行的node节点的名称 传到函数传到ui去
    function<void(QList<QString> nodeName_list)> nodeName_listCallBack=nullptr;
    //sukai 收到的所有数据 传到函数传到ui去
    function<void(QString msgba)> msgba_CallBack=nullptr;
    // todo sukai 2022-01-22  接收授权码服务验证结果
     function<void(QString registerServiceResult)> registerServiceResult_CallBack=nullptr;

    //目标位置
    Instruction targetInstruction;

    //储存上一条脚本执行完成后需要给plc发送的消息，默认不发送消息：EMPTYPLC
    QString up_sendplctypemsg="EMPTYPLC";
    //目标点靠近精度
    double isClose_resultVariance=0.000001;
    //定时执行脚本的计数器
    int ex = 0;
    int blocksize = 0;
    int cmd = 0;
    QString strMsg="";

public:
    //数据恢复
    int kSDemoDlg_testInfo_flg=1;
    int kSDemoDlg_dictionarie_flg=1;
    int kSDemoDlg_task_pose_list_flg=1;
    int kSDemoDlg_task_time_list_flg=1;
    int kSDemoDlg_task_costmapLayer_list_flg=1;

public:
    //发送数据给plc，回调
    function<void(QString msg)> sendPlcMsgCallBack=nullptr;

    //指令队列
    queue<Instruction> instructionQueue;
    //是否是第一次
    bool isFirst = true;
    //是暂停执行
    bool isSTOPT = false;
    //iimtData.h结构体用来保存数据
    IIMT_Data iimtData;
    //[路点数据   数据库：TABLE_OR_ROOM_POSE]
    TestInfo testInfo;
    //vector<TestInfo> testInfos;
    QList<TestInfo> testInfos;
    QList<QMap<QString, QString> > maptestInfos_list;
    //【字典数据  数据库 TABLE_DICTIONARES】
    Dictionaries dictionaries;
    QList<Dictionaries> dictionaries_s;
    std::map<QString, QString> dictionariesMap;
    std::map<QString, QString> dictionariesMap_ui;
    QList<QMap<QString, QString> > mapdictionarie_list;
    //执行路点任务 数据库 TABLE_TASKPOSE 多机调度 多机联动时，把testInfo表对应数据的Status取出来，如果状态为1就 查找TargetName+备用点; 路点数据保存时，对应n个机器人就保存n-1个备用点，保存取餐点
    TaskPOSE taskPOSE;
    QList<TaskPOSE> taskPOSEs;
    QList<QMap<QString, QString>> maptaskPOSEMaps_list;
    //定时任务  [ 数据库  TABLE_TASK]
    Table_Task table_Task;
    QList<Table_Task> Table_Tasks;
    QList<QMap<QString, QString>> mapTable_TaskMaps_list;
    //虚拟墙  [ 数据库  TABLE_COSTMAPLAYER]
    CostmapLayer costmapLayer;
    QList<CostmapLayer> costmapLayers;
    QList<QMap<QString, QString>> mapTable_CostmapLayer_list;
    //到达点位后返回的数据
    ArriveRobot arriveRobot;
    //获取地图名称
    QList<MapName> mapNames;
    //获取node节点名字
    QList<QString> nodeName_list;
    QList<QMap<QString,std::vector<std::string>>> mapNames_list;
    //机器人的一些基本信息
    Robot_info robot_info;
    //小车的运行状态
    QString robot_status = "";
    //静态方法返回当前实例
   // static shared_ptr<IIMTDriver> getInstance();
public:

    ~IIMTDriver();

    static IIMTDriver * getInstance(){
                if(instance == nullptr){
                    m->lock();
                    //懒汉式
                    if(instance == nullptr){
                        instance = new IIMTDriver();
                    }
                    m->unlock();
                }
                return instance;
            }


    //连接机器人
    void connectToRobot(QString ip,int port);
    //断开连接
    void disConnectToRobot();
    //设置回调函数
    void setConnectCallBack(function<void()> connectCallBack);
    //设置断开连接回调
    void setDisConnectCallBack(function<void()> disConnectCallBack);

    //管理接收到的数据
    void managemsg();

    //-----------------传到函数传到ui去------------------------
    //sukai 获取地图名称 传到函数传到ui去
    void setMapNames_listCallBack(function<void(QList<QMap<QString,std::vector<std::string> > > mapNames_list)> mapNames_list_CallBack1);
    //sukai 到达点位后返回的数据 传到函数传到ui去
    void setArriveRobotCallBack(function<void(ArriveRobot arriveRobot)> arriveRobot_CallBack1);
    //sukai 机器人的一些基本信息 传到函数传到ui去
    void setRobot_infoCallBack(function<void(Robot_info robot_info)> robot_info_CallBack1);
    //sukai 小车的运行状态 传到函数传到ui去
    void setRobot_statusCallBack(function<void(QString robot_status)> robot_status_CallBack1);
    //sukai 保存地图后反馈传到ui去
    void setRobot_saveGmappingMap_CallBack(function<void(SaveGmappingMap saveGmappingMap)> robot_saveGmappingMap_CallBack1);
    //sukai 路点数据 传到函数传到ui去
    void setTestInfos_listCallBack(function<void(QList<TestInfo> testInfos)> maptestInfos_list_CallBack1);
    //sukai 字典数据 传到函数传到ui去
    void setDictionarie_listCallBack(function<void(QList<Dictionaries> dictionaries_s)> mapdictionarie_list_CallBack1);
    //sukai 执行路点任务 传到函数传到ui去
    void setTaskPOSECallBack(function<void(QList<TaskPOSE> taskPOSEs)> maptaskPOSEMaps_list_CallBack1);
    //sukai 定时任务 传到函数传到ui去
    void setTime_taskCallBack(function<void(QList<Table_Task> Time_Tasks)> mapTable_time_task_list_CallBack1);

    //sukai 获取所有运行的node节点的名称 传到函数传到ui去
    void setNodeName_listCallBack(function<void(QList<QString> nodeName_list)> nodeName_listCallBack1);
    //sukai 收到的所有数据 传到函数传到ui去
     void setMsgba_CallBack(function<void(QString msgba)> msgba_CallBack1);

    //------------------传到编辑类------------------------

     // todo sukai 2022-01-22  接收授权码服务验证结果
      void setRegisterServiceResult_CallBack(function<void(QString registerServiceResult)> registerServiceResult_CallBack1);

    //sukai 路点数据 传到编辑类 KSDemoDlg 中                      QList<QMap<QString, QString>> maptestInfos_list;
    void setKSDemoDlg_testInfos_listlistCallBack(function<void(QList<QMap<QString, QString> >  kSDemoDlg_testInfos_list_CallBack)> kSDemoDlg_testInfos_list_CallBack1);
    //sukai 字典数据 传到编辑类 KSDemoDlgtaskparamer 中
    void setKSDemoDlg_dictionarie_listCallBack(function<void(QList<QMap<QString, QString> > kSDemoDlg_dictionarie_list_CallBack)> kSDemoDlg_dictionarie_list_CallBack1);
    //sukai 执行路点任务 传到编辑类 KSDemoDlgtask 中
    void setKSDemoDlg_task_poseCallBack(function<void(QList<QMap<QString, QString> > kSDemoDlg_task_pose_list_CallBack)> kSDemoDlg_task_pose_list_CallBack1);
    //sukai 定时任务 传到编辑类 KSDemoDlgtaskTime 中
    void setKSDemoDlg_task_timeCallBack(function<void(QList<QMap<QString, QString> > kSDemoDlg_task_time_list_CallBack)> kSDemoDlg_task_time_list_CallBack1);
    //sukai 虚拟墙 传到编辑类 KSDemoDlgtaskTime 中
    void setKSDemoDlg_task_costmapLayerCallBack(function<void(QList<QMap<QString, QString> > kSDemoDlg_task_costmapLayer_list_CallBack)> kSDemoDlg_task_costmapLayer_list_CallBack1);




    //sukai 设置返回函数
    void setCallBack();
    //------------------------------------------

    //发送数据给无人车
    void sendMsg(QString msg);
    //===================================================================
    //解析Json
    void  parseJson(QString &msgba);
    //todo sukai 2021-11-04 获取marker点位列表,名字
    void  api_markers_query_name_list(QJsonObject &jsonObject);

    //todo sukai 2021-11-04 获取设置的参数
    void  api_get_params(QJsonObject &jsonObject);

    // todo sukai 2021-11-04  小车当前的运行状态 调一次返回一次
    void  api_robot_status_read(QJsonObject &jsonObject);
    // todo sukai 2021-11-04  当状态较之前改变时会自动返回数据
    void  api_car_robot_status(QJsonObject &jsonObject);

    //todo sukai 2021-11-04  每到达一个点位就会返回对应的数据
    void  api_robot_arriveStatus(QJsonObject &jsonObject);
    //todo sukai 2021-11-04 获所有地图名称  {"mapName":"indoor","robotfloor":"1,2,3,4..."}
    void  api_getMapNamelist(QJsonObject &jsonObject);
    //todo sukai 2021-11-07 获取任务表数据
    void  api_taskpose_query_list(QJsonObject &jsonObject);
    //todo sukai 2021-11-07 定时任务
    void  api_time_query(QJsonObject &jsonObject);
    //todo sukai 2022-01-17 虚拟墙数据
    void  api_costmapLayer_query(QJsonObject &jsonObject);
    //todo sukai 2021-11-25 保存地图反馈
    void  api_saveGmappingMap(QJsonObject &jsonObject);
    //todo sukai 2021-11-30 获取所有运行的 node节点的名称
    void  api_nodeName_List(QJsonObject &jsonObject);
    // todo sukai 2022-01-22  接收授权码服务验证结果
    void  api_registerServiceResult(QJsonObject &jsonObject);
    //=================================================
    //在指定位置添加marker.
    void  api_markers_insert_by_pose(QJsonObject &jsonObject);

    // 获取点位摘要信息
    void  api_markers_query_brief(QJsonObject &jsonObject);

    //获取当前地图中的点位数量。
    void  api_markers_count(QJsonObject &jsonObject);

    // 调用接口可以获取机器人的一些基本信息。
    void  api_robot_info(QJsonObject &jsonObject);

    // 获得机器人当前的全局状态
    void  api_robot_status(QJsonObject &jsonObject);

    // 接口 9 请求机器人实时数据
    void  api_robot_data(QJsonObject &jsonObject);

    //todo sukai 2021-11-05 字符串分割函数
    std::vector<std::string> split(std::string pattern,std::string str);

    //===================================================================
    //===================================================================
    //发送数据给plc，回调
    void setSendPlcMsgCallBack(function<void(QString msg)> sendPlcMsgCallBack);
    //movej移动 加速度：a,速度v, 时间：t,交融半径： r waitTime:（定时执行此脚本）执行当前这条脚本时需要等待的时间 等待时间计算为当前服务器每次返回数据的频率的时间乘以waitTime，sendtypemsg:此脚本执行完成后需要发送给plc的消息,digitalStatus:执行该脚本时，当前对应的夹抓的状态
    void movej(double joints[6],double a, double v,double t, double r, int waitTime,QString sendtypemsg,int digitalStatus);
    //movel移动 加速度：a,速度v, 时间：t,交融半径： r waitTime:（定时执行此脚本）执行当前这条脚本时需要等待的时间 等待时间计算为当前服务器每次返回数据的频率的时间乘以waitTime，sendtypemsg:此脚本执行完成后需要发送给plc的消息,digitalStatus:执行该脚本时，当前对应的夹抓的状态
    void movel(double pose[6],double a, double v,double t, double r, int waitTime,QString sendtypemsg,int digitalStatus);
    //movep 加速度：a,速度v, 时间：t,交融半径： r waitTime:（定时执行此脚本）执行当前这条脚本时需要等待的时间 等待时间计算为当前服务器每次返回数据的频率的时间乘以waitTime，sendtypemsg:此脚本执行完成后需要发送给plc的消息,digitalStatus:执行该脚本时，当前对应的夹抓的状态
    void movep(double *pose, double a, double v,double t, double r,int waitTime,QString sendtypemsg,int digitalStatus);
    //movec 加速度：a,速度v, 时间：t,交融半径： r waitTime:（定时执行此脚本）执行当前这条脚本时需要等待的时间 等待时间计算为当前服务器每次返回数据的频率的时间乘以waitTime，sendtypemsg:此脚本执行完成后需要发送给plc的消息,digitalStatus:执行该脚本时，当前对应的夹抓的状态
    void movec(double *pose, double a, double v,double t, double r,int waitTime,QString sendtypemsg,int digitalStatus);
    //解析机器人返回数据
    void parseData(QByteArray &data,IIMT_Data &iimtData);
    //添加运动指令 加速度：a,速度v, 时间：t,交融半径： r waitTime:（定时执行此脚本）执行当前这条脚本时需要等待的时间 等待时间计算为当前服务器每次返回数据的频率的时间乘以waitTime，sendtypemsg:此脚本执行完成后需要发送给plc的消息,digitalStatus:执行该脚本时，当前对应的夹抓的状态
    void addInstruction(MOVETYPE movetype,double data[6],double a,double v,double t, double r,int waitTime,QString sendtypemsg,int digitalStatus);
    //添加io指令 int num ：端口号, int status 状态 waitTime:（定时执行此脚本）执行当前这条脚本时需要等待的时间 等待时间计算为当前服务器每次返回数据的频率的时间乘以waitTime，sendtypemsg:此脚本执行完成后需要发送给plc的消息,digitalStatus:执行该脚本时，当前对应的夹抓的状态
    void addDigitalInstruction(MOVETYPE movetype,  int num, int status,int waitTime,QString sendtypemsg,int digitalStatus);
    //是否执行下一条指令
    void decideExcuteNextInstruction(IIMT_Data &iimtData);
    //执行下一条指令及给plc发送指令
    void excuteNextInstructionAndsendPlcTypeMsg(IIMT_Data &iimtData);
    //执行下一条指令
    void excuteNextInstruction();
    //模拟测试执行下发指令 是否执行下一条指令
    void decideExcuteNextInstructionTest();
    //更新目标指令
    void updateTargetInstruction(Instruction &instruction);
    //io 直接发送io脚本，不加入队列
    void digital(int data[2]);
    //io digital ioInput 添加到队列中发送 waitTime:（定时执行此脚本）执行当前这条脚本时需要等待的时间 等待时间计算为当前服务器每次返回数据的频率的时间乘以waitTime，sendtypemsg:此脚本执行完成后需要发送给plc的消息,digitalStatus:执行该脚本时，当前对应的夹抓的状态
    void digitalToQueue(int data[2],int waitTime,QString sendtypemsg,int digitalStatus);
    //io digital ioInput 添加到队列中发送,sendtypemsg:此脚本执行完成后需要发送给plc的消息,digitalStatus:执行该脚本时，当前对应的夹抓的状态
    void digitalToQueueNew(int num,int status, int waitTime, QString sendtypemsg,int digitalStatus);
    //删除Queue数据
    void clearInstructionQueue();
    //初始化参数
    void initIImtDriver();

};


#endif //IIMTDriverCPP_IIMTDriver_H
